{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "e46f9823-e037-461e-89b6-b5d02bcbdb00",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter as tk\n",
    "\n",
    "root = tk.Tk()\n",
    "root.title('Gaussian mixture clustering')\n",
    "root.geometry('300x90')\n",
    "\n",
    "labelPath = tk.Label(root, text='path to inputfile:', justify=tk.RIGHT, anchor='e', width=100)\n",
    "labelPath.place(x=20, y=10, width=100, height=30)\n",
    "\n",
    "varName = tk.StringVar(root, value='')\n",
    "entryName = tk.Entry(root, width=150, textvariable=varName)\n",
    "entryName.place(x=130, y=10, width=150, height=30)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "cc25abe2-78f7-4b1e-aca4-ab4f550c29e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import xlrd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from numpy import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "64b5c221-6022-4812-9aec-16e80000fb20",
   "metadata": {},
   "outputs": [],
   "source": [
    "#读取excel数据集\n",
    "#dots=[]\n",
    "def read_dots(_list, path):\n",
    "  xl = xlrd.open_workbook(path)\n",
    "  table=xl.sheets()[0]\n",
    "  nrows=table.nrows\n",
    "  for i in range(0,nrows):\n",
    "      dot=[table.cell(i,0).value,table.cell(i,1).value]\n",
    "      _list.append(dot)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "8c01293c-d27c-4acc-9fd1-28f828670e92",
   "metadata": {},
   "outputs": [],
   "source": [
    "#二维高斯概率密度函数（mu, sigma）在x处的概率值\n",
    "def prob(x, mu, sigma):     \n",
    "    n = shape(x)[1]\n",
    "    expOn = float(-0.5*(x-mu)*(sigma.I)*((x-mu).T))\n",
    "    divBy = pow(2*pi, n/2)*pow(linalg.det(sigma), 0.5)\n",
    "    return pow(e, expOn)/divBy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "e15f02ac-346a-4bbc-a271-f0b21d5ae5c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#EM算法优化\n",
    "def EM(dataMat, maxIter=100):\n",
    "    m, n = shape(dataMat)    #m行n列\n",
    "\n",
    "  #初始化假设（三个二维高斯概率密度函数）\n",
    "    alpha = [1/3, 1/3, 1/3]                              #假设混合系数是相同的\n",
    "    mu = [dataMat[5, :], dataMat[21, :], dataMat[26, :]]\n",
    "    sigma = [mat([[0.1, 0], [0, 0.1]]) for x in range(3)]\n",
    "    gamma = mat(zeros((m, 3)))\n",
    "\n",
    "    for i in range(maxIter):\n",
    "\n",
    "  #E过程\n",
    "        for j in range(m):\n",
    "            sumAlphaMulP = 0\n",
    "            for k in range(3):\n",
    "                gamma[j, k] = alpha[k]*prob(dataMat[j, :], mu[k], sigma[k])\n",
    "                sumAlphaMulP += gamma[j, k]\n",
    "            for k in range(3):\n",
    "                gamma[j, k] /= sumAlphaMulP\n",
    "        sumGamma = sum(gamma, axis=0)\n",
    "\n",
    "  #M过程\n",
    "        for k in range(3):\n",
    "            mu[k] = mat(zeros((1, n)))\n",
    "            sigma[k] = mat(zeros((n, n)))\n",
    "            for j in range(m):\n",
    "                mu[k] += gamma[j, k]*dataMat[j, :]\n",
    "            mu[k] /= sumGamma[0, k]\n",
    "            for j in range(m):\n",
    "                sigma[k] += gamma[j, k]*(dataMat[j, :]-mu[k]).T*(dataMat[j, :]-mu[k])\n",
    "            sigma[k] /= sumGamma[0, k]\n",
    "            alpha[k] = sumGamma[0, k]/m\n",
    "            \n",
    "    return gamma\n",
    " \n",
    "def initCentroids(dataMat, k):  \n",
    "    numSamples, dim = dataMat.shape  \n",
    "    centroids = zeros((k, dim))  \n",
    "    for i in range(k):  \n",
    "        index = int(random.uniform(0, numSamples))  \n",
    "        centroids[i, :] = dataMat[index, :]  \n",
    "    return centroids  \n",
    "\n",
    "def gaussianCluster(dataMat):\n",
    "    m, n = shape(dataMat)\n",
    "  # 每个样本的所属的簇，以及分到该簇对应的响应度 \n",
    "    centroids = initCentroids(dataMat, m)  \n",
    "    clusterAssign = mat(zeros((m, 2)))\n",
    "    gamma = EM(dataMat)\n",
    "    for i in range(m):\n",
    "  # amx返回矩阵最大值，argmax返回矩阵最大值所在下标\n",
    "        clusterAssign[i,:] = argmax(gamma[i, :]), amax(gamma[i, :])\n",
    "  #更新簇 \n",
    "    for j in range(m):  \n",
    "        pointsInCluster = dataMat[nonzero(clusterAssign[:, 0].A == j)[0]]  \n",
    "        centroids[j, :] = mean(pointsInCluster, axis = 0)  \n",
    "    return centroids,clusterAssign\n",
    " \n",
    "def showCluster(dataMat, k, centroids, clusterAssment):  \n",
    "    numSamples, dim = dataMat.shape  \n",
    "    if dim != 2:  \n",
    "        print(\"Sorry! I can not draw because the dimension of your data is not 2!\") \n",
    "        return 1  \n",
    "  \n",
    "    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']  \n",
    "    if k > len(mark):  \n",
    "        print(\"Sorry! Your k is too large!\")\n",
    "        return 1  \n",
    "  \n",
    "    # draw all samples  \n",
    "    for i in range(numSamples):  \n",
    "        markIndex = int(clusterAssment[i, 0])  \n",
    "        plt.plot(dataMat[i, 0], dataMat[i, 1], mark[markIndex])  \n",
    "  \n",
    "    mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']  \n",
    "    # draw the centroids  \n",
    "    for i in range(k):  \n",
    "        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)  \n",
    "  \n",
    "    plt.show() "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "ae64045c-ca6a-4cd0-8bd7-b8b73ec7f853",
   "metadata": {},
   "outputs": [],
   "source": [
    "#read_dots(dots)\n",
    "#dots=mat(dots)\n",
    "#centroids,clusterAssign = gaussianCluster(dots)\n",
    "#print(clusterAssign)\n",
    "#showCluster(dots,3,centroids,clusterAssign)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "d53a496d-425e-418e-bf8f-e79f6baa097d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def GDraw():\n",
    "    path = entryName.get()\n",
    "    dots = []\n",
    "    read_dots(dots, path)\n",
    "    dots = mat(dots)\n",
    "    centroids, clusterAssign = gaussianCluster(dots)\n",
    "    showCluster(dots, 3, centroids, clusterAssign)\n",
    "\n",
    "buttonDraw = tk.Button(root, text='result', command=GDraw)\n",
    "buttonDraw.place(x=125, y=50, width=60, height=30)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "e6ca695c-51a6-477b-a1fc-8c61f2d403b9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "root.mainloop()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
